/*
* Copyright 2010 The WicketForge-Team
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package wicketforge.util;
import com.intellij.codeInsight.AnnotationUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.searches.ClassInheritorsSearch;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.Query;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import wicketforge.Constants;
import java.util.Collection;
/**
* Collection of utility methods for the plugin.
*/
public final class WicketPsiUtil {
private WicketPsiUtil() {
}
/**
* Returns true if the passed PsiClass instance is a subclass of Wicket's Component class.
* This method works with Wicket versions through 1.3.
*
* @param clazz PsiClass
* @return boolean
*/
public static boolean isWicketComponent(@NotNull PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_COMPONENT);
}
/**
* Returns true if the passed PsiClass instance is a Wicket ResourceModel class.
* This method works with Wicket versions through 1.3.
*
* @param clazz PsiClass
* @return boolean
*/
public static boolean isWicketResourceModel(@NotNull PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_RESOURCEMODEL, Constants.WICKET_STRINGRESOURCEMODEL);
}
/**
* Returns true if the PsiClass is an instance of a wicket page.
*
* @param clazz PsiClass
* @return true if instance of a wicket page
*/
public static boolean isWicketPage(@NotNull final PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_PAGE);
}
/**
* Returns true if the PsiClass is an instance of a wicket panel.
*
* @param clazz PsiClass
* @return true if instance of a wicket panel
*/
public static boolean isWicketPanel(@NotNull final PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_PANEL, Constants.WICKET_FORMCOMPONENTPANEL);
}
/**
* Returns true if the PsiClass is an instance of a wicket border.
*
* @param clazz PsiClass
* @return true if instance of a wicket border
*/
public static boolean isWicketBorder(@NotNull final PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_BORDER);
}
/**
* Returns true if the PsiClass is an instance of a wicket Page or WebMarkupContainerWithAssociatedMarkup.
*
* @param clazz PsiClass
* @return true if instance of a wicket Page or WebMarkupContainerWithAssociatedMarkup
*/
public static boolean isWicketComponentWithAssociatedMarkup(@NotNull final PsiClass clazz) {
return isInheritor(clazz, Constants.WICKET_PAGE, Constants.WICKET_PANEL, Constants.WICKET_FORMCOMPONENTPANEL, Constants.WICKET_BORDER);
}
/**
* Returns true if the PsiClass is an instance of a MarkupContainer.
*
* @param clazz PsiClass
* @return true if instance of a MarkupContainer
*/
public static boolean isMarkupContainer(@NotNull final PsiClass clazz) {
return isInheritor(clazz, "org.apache.wicket.MarkupContainer");
}
private static boolean isInheritor(@NotNull PsiClass candidateClass, @NotNull String... baseClassQualifiedNames) {
PsiClass workClass = candidateClass;
while (workClass != null) {
String candidateClassQualifiedName = workClass.getQualifiedName();
if (candidateClassQualifiedName != null) { // just for first time, cause anonymous class returns null...
for (String baseClassQualifiedName : baseClassQualifiedNames) {
if (baseClassQualifiedName.equals(candidateClassQualifiedName)) {
return true;
}
}
}
workClass = workClass.getSuperClass();
}
return false;
/* same (safer?) implementation thru ideas classes...
Project project = candidateClass.getProject();
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
for (String baseClassQualifiedName : baseClassQualifiedNames) {
PsiClass superClass = psiFacade.findClass(baseClassQualifiedName, GlobalSearchScope.allScope(project));
if (superClass != null && candidateClass.isInheritor(superClass, true)) {
return true;
}
}
return false;
*/
}
/**
* @param element PsiElement
* @return PsiClass of Page/Pane from element
*/
@Nullable
public static PsiClass getParentWicketClass(@NotNull PsiElement element) {
PsiClass psiClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false);
while (psiClass != null) {
if (WicketPsiUtil.isWicketComponentWithAssociatedMarkup(psiClass)) {
return getConcreteClass(psiClass);
}
psiClass = PsiTreeUtil.getParentOfType(psiClass, PsiClass.class, true);
}
return null;
}
@Nullable
private static PsiClass getConcreteClass(@Nullable PsiClass psiClass) {
while (psiClass != null && psiClass.getName() == null) { // parentWicketClass needs a name (ex anonymous classes dont have) so we get its superclass (issue 48)
psiClass = psiClass.getSuperClass();
}
return psiClass;
}
@Nullable
public static PsiClass findWicketApplicationClass(@NotNull Project project) {
PsiClass wicketApplicationClass =
JavaPsiFacade.getInstance(project).findClass(Constants.WICKET_APPLICATION, GlobalSearchScope.allScope(project));
if (wicketApplicationClass == null) {
return null;
}
Query<PsiClass> query = ClassInheritorsSearch.search(wicketApplicationClass, GlobalSearchScope.allScope(project), true);
Collection<PsiClass> matches = query.findAll();
if (matches.isEmpty()) {
return null;
}
// iterate over the matches and return the first class we find that isn't in org.apache.wicket
for (PsiClass match : matches) {
String qualifiedName = match.getQualifiedName();
if (qualifiedName != null && !qualifiedName.contains("org.apache.wicket")) {
return match;
}
}
return null;
}
/**
* @param callExpression
* @return PsiAnonymousClass or referenced PsiClass or null
*
* This is *not* equal to PsiNewExpression.getClassOrAnonymousClassReference()
*/
@Nullable
public static PsiClass getClassToBeCreated(@NotNull PsiCallExpression callExpression) {
PsiClass result = null;
if (callExpression instanceof PsiNewExpression) {
PsiNewExpression newExpression = (PsiNewExpression) callExpression;
// first check if referenced var is a anonymous class, then we have our result
result = newExpression.getAnonymousClass();
if (result == null) {
// if not anonymous -> resolve concrete class as result
PsiJavaCodeReferenceElement referenceElement = newExpression.getClassReference();
if (referenceElement != null) {
PsiElement resolvedElement = referenceElement.resolve();
if (resolvedElement != null && resolvedElement instanceof PsiClass) {
result = (PsiClass) resolvedElement;
}
}
}
} else if (callExpression instanceof PsiMethodCallExpression) {
PsiMethodCallExpression methodCallExpression = (PsiMethodCallExpression) callExpression;
PsiMethod psiMethod = methodCallExpression.resolveMethod();
if (psiMethod != null && AnnotationUtil.findAnnotation(psiMethod, Constants.WICKETFORGE_COMPONENT_FACTORY) != null) {
result = PsiUtil.resolveClassInClassTypeOnly(psiMethod.getReturnType());
}
}
return result;
}
@Nullable
public static PsiExpression getWicketIdExpressionFromArguments(@NotNull PsiCallExpression expression) {
PsiExpressionList expressionList = expression.getArgumentList();
if (expressionList != null) {
PsiExpression[] psiExpressions = expressionList.getExpressions();
if (psiExpressions.length > 0) {
return psiExpressions[0];
}
}
return null;
}
@Nullable
public static String getWicketIdFromExpression(@NotNull PsiExpression expression) {
Object object = JavaConstantExpressionEvaluator.computeConstantExpression(expression, false);
return object instanceof String ? (String) object : null;
}
/**
* @param element
* @return true if element is in library
*/
public static boolean isInLibrary(@Nullable PsiElement element) {
if (element != null) {
VirtualFile vf = PsiUtil.getVirtualFile(element);
if (vf != null) {
return WicketFileUtil.isInLibrary(vf, element.getProject());
}
}
return false;
}
}